#include "rdx_pccm_env.hpp"

void *rdxPCCMCallEnvironmentInternal::GetBP() const
{
	return m_bp;
}

void *rdxPCCMCallEnvironmentInternal::GetPRV() const
{
	return m_prv;
}

rdxCObject *rdxPCCMCallEnvironmentInternal::GetRes(rdxLargeUInt resIndex) const
{
	return m_method->resArgs->Element(resIndex).Modify();
}

rdxCMethod *rdxPCCMCallEnvironmentInternal::GetMethodRes(rdxLargeUInt resIndex) const
{
	return static_cast<rdxCMethod*>(m_method->resArgs->Element(resIndex).Modify());
}

void rdxPCCMCallEnvironmentInternal::EnterMethod(rdxCMethod *method, void *prvBase, void *frameBase, rdxLargeUInt callingInstr)
{
	// TODO MUSTFIX: Null checks on method and bytecode?
	rdxSRuntimeStackFrame currentFrame;
	currentFrame.bp = reinterpret_cast<rdxSRuntimeStackFrame*>(m_bp);
	currentFrame.ip = static_cast<const rdxUInt8 *>(RDX_CNULL) + callingInstr + 1;
	currentFrame.method = rdxWeakRTRef(rdxCMethod)(rdxObjRef_CSignal_DataPointer, method);
	currentFrame.prv = reinterpret_cast<rdxURuntimeStackValue*>(m_prv);

	rdxNativeCallback cb = method->m_native.nativeCall;

	if(!method->m_native.isNativeCall)
	{
		if(method->bytecode.IsNull())
			rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
			//THROWEXCEPTIONDICT(rdxX_NullReferenceException);

		// Re-enter
		rdxSRuntimeStackFrame newFrame;
		if(!rdxEnterMethodInline(method->ObjectInfo()->ownerObjectManager, rdxWeakRTRef(rdxCMethod)(rdxObjRef_CSignal_DataPointer, method), &currentFrame, frameBase, m_thread->stackBytes,
			reinterpret_cast<rdxURuntimeStackValue*>(prvBase), &newFrame))
		{
			rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
			//THROWEXCEPTIONDICT(rdxX_StackOverflowException);
		}

		if(newFrame.method->m_native.pccmCallback)
		{
			m_thread->frame = newFrame;
			m_returnStatus = rdxRS_Active;
			return;
		}

		m_bp = newFrame.bp;
		m_prv = newFrame.prv;
		m_resumeInstr = 0;
		m_method = newFrame.method.Data();
	}
	else
	{
		if(cb == RDX_CNULL)
			rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
			//THROWEXCEPTIONDICT(rdxX_NullReferenceException);

		m_thread->frame = currentFrame;
		m_thread->insertionPoint = frameBase;
		m_thread->activeNativeMethod = rdxWeakRTRef(rdxCMethod)(rdxObjRef_CSignal_DataPointer, method);

		int status = cb(m_ctx, method->ObjectInfo()->ownerObjectManager,
			rdxWeakHdl(rdxCMethod)(rdxObjRef_CSignal_DataPointer, const_cast<rdxCMethod*>(method)),
			rdxWeakHdl(rdxCRuntimeThread)(rdxObjRef_CSignal_DataPointer, m_thread), prvBase);
		m_thread->activeNativeMethod = rdxWeakRTRef(rdxCMethod)::Null();

		if(status <= 0)
		{
			m_thread->frame = currentFrame;
			m_returnStatus = static_cast<rdxERuntimeState>(status);
			return;
		}
	}
}

void rdxPCCMCallEnvironmentInternal::SwitchScanObjRef(const rdxCObject *objRef, rdxLargeUInt casesResIndex, rdxLargeUInt numCases, rdxLargeUInt callingInstr)
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
}

bool rdxPCCMCallEnvironmentInternal::CheckInherits(const rdxCObject *obj, rdxLargeUInt typeResIndex) const
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
	return false;
}

bool rdxPCCMCallEnvironmentInternal::CheckEnum(const rdxSRuntimeEnum &value, rdxLargeUInt typeResIndex) const
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
	return false;
}

bool rdxPCCMCallEnvironmentInternal::CheckEnum(RDX_ENUM_TYPE value, rdxLargeUInt typeResIndex) const
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
	return false;
}

void rdxPCCMCallEnvironmentInternal::SetStandardException(rdxECommonExceptions ex, rdxLargeUInt instr)
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
}

void rdxPCCMCallEnvironmentInternal::SetException(rdxCException *ex, rdxLargeUInt instr)
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
}

rdxCMethod *rdxPCCMCallEnvironmentInternal::GetInterfaceCallMethod(void *stackLoc, rdxLargeUInt vstIndex, rdxLargeUInt methodResIndex)
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
	return RDX_CNULL;
}

void rdxPCCMCallEnvironmentInternal::ImmediateResObj(rdxBaseRTRef &vregBase, rdxLargeUInt resIndex)
{
	rdxCObject *obj = m_method->resArgs->Element(resIndex).Modify();
	vregBase.AssignRef(rdxBaseRef_ConSignal<false, true>::Value, rdxRefConverter<rdxBaseRTRef::DerefPODType>::Convert(obj));
}

rdxCObject *rdxPCCMCallEnvironmentInternal::GetStackRoot() const
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
	return RDX_CNULL;
}

bool rdxPCCMCallEnvironmentInternal::CreateInstanceFromRes(rdxCObject **objRef, rdxLargeUInt typeResIndex, const rdxLargeUInt *dimensions, rdxLargeUInt numDimensions, rdxLargeUInt instrNum)
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
	return false;
}

rdxCMethod *rdxPCCMCallEnvironmentInternal::GetVirtualMethod(const rdxCObject *vreg, rdxLargeUInt methodResIndex) const
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
	return RDX_CNULL;
}

bool rdxPCCMCallEnvironmentInternal::CheckImplements(const rdxCObject *vreg, rdxLargeUInt interfaceResIndex) const
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
	return false;
}

void rdxPCCMCallEnvironmentInternal::ExitFunction()
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
}

rdxLargeUInt rdxPCCMCallEnvironmentInternal::GetResumeInstruction() const
{
	return this->m_resumeInstr;
}

bool rdxPCCMCallEnvironmentInternal::CheckConversion(const rdxCObject *objRef, const rdxCStructuredType *st) const
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
	return false;
}

void rdxPCCMCallEnvironmentInternal::SelectCase(rdxLargeUInt caseNo, rdxLargeUInt callingInstr)
{
	rdxDebugBreak(rdxBREAKCAUSE_Unimplemented);
}
